#include <gpiod.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include "record.h"
#include "config.h"
#include "token.h"
#include "http.h"
#include <cjson/cJSON.h>

#define GPIO_LINE 9 // 定义GPIO线的编号，这里是PF9

typedef struct {
    char* data;
    size_t size;
    size_t capacity;
} AudioBuffer;

void audio_buffer_init(AudioBuffer* buffer) {
    buffer->data = NULL;
    buffer->size = 0;
    buffer->capacity = 0;
}

void audio_buffer_free(AudioBuffer* buffer) {
    free(buffer->data);
    buffer->data = NULL;
    buffer->size = 0;
    buffer->capacity = 0;
}

int audio_buffer_write(AudioBuffer* buffer, const char* data, size_t size) {
    if (buffer->size + size > buffer->capacity) {
        size_t new_capacity = (buffer->capacity + size) * 2;
        char* new_data = (char*)realloc(buffer->data, new_capacity);
        if (!new_data) {
            return -1; // 分配失败
        }
        buffer->data = new_data;
        buffer->capacity = new_capacity;
    }
    memcpy(buffer->data + buffer->size, data, size);
    buffer->size += size;
    return 0; // 成功
}

char* send_request(char* token, char* audio, size_t size) {
    char* url = NULL;
    asprintf(&url, "http://vop.baidu.com/server_api?cuid=hqyj&token=%s", token);
    struct curl_slist* headers = NULL;
    headers = curl_slist_append(headers, "Content-Type: audio/pcm; rate=16000");
    char* response = post(url, headers, audio, &size);
    free(url);
    curl_slist_free_all(headers);
    return response;
}

void process_response(char* response, size_t size) {
    cJSON *json = cJSON_ParseWithLength(response, size);
    if (!json) {
        fprintf(stderr, "解析 JSON 失败: [%s]\n", cJSON_GetErrorPtr());
        return;
    }
    cJSON* err_no = cJSON_GetObjectItem(json, "err_no");
    if (!err_no) {
        fprintf(stderr, "err_no 字段不存在\n");
        cJSON_Delete(json);
        return;
    }
    if (err_no->valueint != 0) {
        cJSON* err_msg = cJSON_GetObjectItem(json, "err_msg");
        if (err_msg) {
            fprintf(stderr, "err_msg: %s\n", err_msg->valuestring);
        }
        cJSON_Delete(json);
        return;
    }
    cJSON *result = cJSON_GetObjectItem(json, "result");
    if (!result) {
        fprintf(stderr, "JSON 格式错误: 找不到'result' 字段\n");
        cJSON_Delete(json);
        return;
    }
    if (cJSON_GetArraySize(result) > 0) {
        cJSON *content = cJSON_GetArrayItem(result, 0);
        printf("result: %s\n", content->valuestring);
    }
    cJSON_Delete(json);
}

int main(void) {
    struct gpiod_chip *chip;
    struct gpiod_line *line;
    int value, last_value;
    snd_pcm_uframes_t period;
    snd_pcm_t* capture = NULL;
    char* buffer = NULL;
    AudioBuffer audio_buffer;
    size_t size;

    audio_buffer_init(&audio_buffer);

    chip = gpiod_chip_open_by_label("GPIOF");
    if (!chip) {
        perror("打开GPIO芯片失败");
        return 1;
    }
    
    line = gpiod_chip_get_line(chip, GPIO_LINE);
    if (!line) {
        perror("获取GPIO线失败");
        gpiod_chip_close(chip);
        return 1;
    }
    
    if (gpiod_line_request_input(line, "key1")) {
        perror("请求将GPIO线设置为输入模式失败");
        gpiod_chip_close(chip);
        return 1;
    }
    
    last_value = gpiod_line_get_value(line);
    
    while (1) {
        value = gpiod_line_get_value(line);
        if (value != last_value) {
            if (value == 0) {
                printf("key pressed\n");
                capture = record_open("hw:0,1", SND_PCM_FORMAT_S16_LE, 1, 16000, &period); // 修改为单声道、16kHz 采样率
                if (!capture) {
                    continue;
                }
                buffer = malloc(snd_pcm_frames_to_bytes(capture, period));
                if (!buffer) {
                    perror("malloc");
                    record_close(capture);
                    continue;
                }
            } else {
                printf("key released\n");
                record_close(capture);
                capture = NULL;
                free(buffer);

                printf("Audio buffer size: %zu bytes\n", audio_buffer.size); // 打印音频缓冲区大小
                cJSON *config = read_config("config.json");
                if (!config) {
                    printf("config: %s\n", cJSON_Print(config));
                    audio_buffer_free(&audio_buffer);
                    return EXIT_FAILURE;
                }
                cJSON* api_key = cJSON_GetObjectItem(config, "api_key");
                cJSON* secret_key = cJSON_GetObjectItem(config, "secret_key");
                if (!api_key || !secret_key) {
                    fprintf(stderr, "配置文件错误: 找不到 'api_key' 或'secret_key' 字段\n");
                    cJSON_Delete(config);
                    audio_buffer_free(&audio_buffer);
                    return EXIT_FAILURE;
                }
                char* token = get_access_token(api_key->valuestring, secret_key->valuestring);
                cJSON_Delete(config);
                if (!token) {
                    fprintf(stderr, "获取 token 失败\n");
                    audio_buffer_free(&audio_buffer);
                    return EXIT_FAILURE;
                }
                char* response = send_request(token, audio_buffer.data, audio_buffer.size);
                free(token);
                if (!response) {
                    fprintf(stderr, "调用百度语音识别 API 失败\n");
                    audio_buffer_free(&audio_buffer);
                    return EXIT_FAILURE;
                }
                process_response(response, audio_buffer.size);
                free(response);
                audio_buffer_free(&audio_buffer);
            }
            last_value = value;
        }
        if (value == 0 && capture) {
            snd_pcm_sframes_t frames = snd_pcm_readi(capture, buffer, period);
            if (frames < 0) {
                fprintf(stderr, "Error from read: %s\n", snd_strerror(frames));
                snd_pcm_recover(capture, frames, 0);
            }
            audio_buffer_write(&audio_buffer, buffer, snd_pcm_frames_to_bytes(capture, frames));
        }
    }
    
    gpiod_line_release(line);
    gpiod_chip_close(chip);
    return 0;
}
